package com.wyl.template.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.wyl.template.domain.common.ResponseResult;
import com.wyl.template.domain.dto.SysPermissionDTO;
import com.wyl.template.domain.dto.SysRoleDTO;
import com.wyl.template.domain.dto.SysRolePermissionDTO;
import com.wyl.template.domain.model.SysPermissionDO;
import com.wyl.template.domain.model.SysRoleDO;
import com.wyl.template.domain.model.SysRolePermissionDO;
import com.wyl.template.domain.model.SysUserDO;
import com.wyl.template.domain.vo.RolePermissionVO;
import com.wyl.template.exception.BusinessException;
import com.wyl.template.exception.ErrorCodeEnum;
import com.wyl.template.mapper.SysRoleMapper;
import com.wyl.template.mapper.SysRolePermissionMapper;
import com.wyl.template.service.SysRolePermissionService;
import com.wyl.template.service.SysRoleService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.subject.Subject;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.ObjectUtils;

import javax.annotation.Resource;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/**
 * <p>
 * 角色表 服务实现类
 * </p>
 *
 * @author wyl
 * @since 2021-06-11
 */
@Service
public class SysRoleServiceImpl extends ServiceImpl<SysRoleMapper, SysRoleDO> implements SysRoleService {

    @Autowired
    private SysRoleMapper roleMapper;


    @Autowired
    private SysRolePermissionService rolePermissionService;

    /**
     * 根据角色名字获得角色信息
     *
     * @param roleName
     * @return
     */
    @Override
    public SysRoleDTO getRolesByName(String roleName) {
        SysRoleDO sysRoleDO = new SysRoleDO();
        sysRoleDO.setRoleName(roleName.trim());
        QueryWrapper<SysRoleDO> queryWrapper = new QueryWrapper<>(sysRoleDO);

        SysRoleDO roleDO = getOne(queryWrapper);
        SysRoleDTO roleDTO = new SysRoleDTO();
        BeanUtils.copyProperties(roleDO, roleDTO);

        return roleDTO;
    }

    /**
     * 根据角色id获得角色信息
     *
     * @param roleId
     * @return
     */
    @Override
    public SysRoleDTO getRolesById(Long roleId) {
//        SysRoleDO sysRoleDO = roleMapper.selectById(roleId);
        SysRoleDO sysRoleDO = getById(roleId);
        SysRoleDTO roleDTO = new SysRoleDTO();
        BeanUtils.copyProperties(sysRoleDO, roleDTO);

        return roleDTO;
    }

    /**
     * 获得用户的角色列表
     *
     * @param userId
     * @return
     */
    @Override
    public List<SysRoleDO> listUserRoles(Long userId) {
        List<SysRoleDO> sysRoleDOS = roleMapper.listUserRoles(userId);
        return sysRoleDOS;
    }

    /**
     * 获得所有角色信息
     *
     * @return
     */
    @Override
    public List<SysRoleDTO> listRoles() {
        List<SysRoleDO> list = list();
        return transferDTO(list);
    }


    /**
     * 根据角色信息，查询关联的权限目录
     *
     * @param roleList
     * @return
     */
    @Override
    public List<RolePermissionVO> listRolesPerssionIn(List<SysRoleDO> roleList) {
        List<Long> ids = new ArrayList<>();
        roleList.forEach(item -> {
            ids.add(item.getId());
        });
        List<SysRolePermissionDTO> dtoList = roleMapper.listRolesPerssionIn(ids);
        Stream<RolePermissionVO> stream = roleList.stream().map(item -> {
            List<SysPermissionDO> permissionDOS = new ArrayList<>();
            dtoList.forEach(dto -> {
                if (!ObjectUtils.isEmpty(dto.getId()) && !ObjectUtils.isEmpty(dto.getPermissionId()) && item.getId().equals(dto.getId())) {
                    SysPermissionDO permissionDO = new SysPermissionDO();
                    permissionDO.setId(dto.getPermissionId());
                    permissionDO.setParentId(dto.getParentId());
                    permissionDO.setMenuName(dto.getMenuName());
                    permissionDOS.add(permissionDO);
                }
            });
            RolePermissionVO resVO = new RolePermissionVO();
            BeanUtils.copyProperties(item, resVO);
            resVO.setPermissionList(permissionDOS);
            return resVO;
        });
        return stream.collect(Collectors.toList());
    }

    /**
     * 更新角色
     *
     * @param rolePermission
     * @return
     */
    @Transactional
    @Override
    public ResponseResult updateRole(RolePermissionVO rolePermission) {
        SysRoleDO roleDO = getSysRoleDO(rolePermission);

        boolean res = updateById(roleDO);
        if(!res){
            throw new BusinessException(ErrorCodeEnum.UPDATE_FAILURE);
        }

        //更新角色关联的权限
        updateRolePermission(rolePermission);

        return ResponseResult.success();
    }

    /**
     * 添加角色
     *
     * @param rolePermission
     * @return
     */
    @Transactional
    @Override
    public ResponseResult addRole(RolePermissionVO rolePermission) {
        // 检查角色唯一性
        SysRoleDO sysRoleDO = lambdaQuery().eq(SysRoleDO::getRoleName, rolePermission.getRoleName()).one();
        if (sysRoleDO != null) {
            return ResponseResult.error(ErrorCodeEnum.ROLE_EXIST);
        }
        Subject subject = SecurityUtils.getSubject();
        SysUserDO currentUser = (SysUserDO) subject.getPrincipal();

        SysRoleDO roleDO = getSysRoleDO(rolePermission);
        roleDO.setCreateBy(currentUser.getId());
        roleDO.setCreateTime(new Date());
        // 保存角色信息
        save(roleDO);
        // 获得当前用户角色信息，得到id赋值给rolePermission，设置角色权限关系
        SysRoleDTO rolesByName = getRolesByName(roleDO.getRoleName());
        rolePermission.setId(rolesByName.getId());

        //保存角色关联的权限
        updateRolePermission(rolePermission);
        return ResponseResult.success();
    }

    /**
     * 拼装角色信息
     * @param rolePermission
     * @return
     */
    private SysRoleDO getSysRoleDO(RolePermissionVO rolePermission){
        Subject subject = SecurityUtils.getSubject();
        SysUserDO currentUser = (SysUserDO) subject.getPrincipal();

        SysRoleDO roleDO = new SysRoleDO();
        BeanUtils.copyProperties(rolePermission,roleDO);
        roleDO.setUpdateBy(currentUser.getId());
        roleDO.setUpdateTime(new Date());
        return roleDO;
    }

    /**
     * 更新角色关联的权限
     * @param rolePermission
     */
    private void updateRolePermission(RolePermissionVO rolePermission){
        //保存角色关联的权限
        List<SysPermissionDO> permissionList = rolePermission.getPermissionList();
        if (permissionList != null && permissionList.size() > 0) {

            List<SysRolePermissionDO> rolePermissionList = new ArrayList<>();

            permissionList.forEach(item->{
                SysRolePermissionDO rolePermissionDO = new SysRolePermissionDO();
                rolePermissionDO.setRoleId(rolePermission.getId());
                rolePermissionDO.setPermissionId(item.getId());
                rolePermissionList.add(rolePermissionDO);
            });

            rolePermissionService.updateRolePermission(rolePermission.getId(), rolePermissionList);
        }
    }

    /**
     * 删除角色
     *
     * @param roleId
     * @return
     */
    @Transactional
    @Override
    public ResponseResult deleteRole(Long roleId) {
        Subject subject = SecurityUtils.getSubject();
        SysUserDO currentUser = (SysUserDO) subject.getPrincipal();

        // 逻辑删除
        lambdaUpdate().eq(SysRoleDO::getId, roleId)
                .set(SysRoleDO::getUpdateBy, currentUser.getId()).set(SysRoleDO::getUpdateTime, LocalDateTime.now()).set(SysRoleDO::getDeleted, 1)
                .update();

        // 删除角色关联的权限
        rolePermissionService.updateRolePermission(roleId, null);

        return ResponseResult.success();
    }

    /**
     * DO 转 DTO
     *
     * @param list
     * @return
     */
    List<SysRoleDTO> transferDTO(List<SysRoleDO> list) {
        List<SysRoleDTO> resList = new ArrayList<>();
        list.stream().forEach(item -> {
            SysRoleDTO permissionDTO = new SysRoleDTO();
            BeanUtils.copyProperties(item, permissionDTO);
            resList.add(permissionDTO);
        });

        return resList;
    }
}
